﻿namespace ColumnOrderingSetup.ItemEventReceiver
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;

    /// <summary>
    /// List Item Events
    /// </summary>
    public class COBackgroundTaskItemEventReceiver : SPItemEventReceiver
    {
        #region Fields

        const string COBACKGROUNDSTATUS = "cobackgroundstatus";
        const string ERRORS = "Errors";
        const string INIT_MESSAGE = "{0} started on {1} at {2}.";
        const int MAXDAYS = 10;
        const int MAXITEMS = 200;
        const string NOT_OK_MESSAGE = "{0} started on {4} at {5}. Ended with errors on {1} at {2} in {3}.";
        const string OK_MESSAGE = "{0} started on {4} at {5}. Completed with no errors on {1} at {2} in {3}.";
        const string TITLE = "Title";

        #endregion Fields

        #region Properties

        string WebUrl
        {
            get;
            set;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// An item was added.
        /// </summary>
        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);

            DateTime startTime = DateTime.Now;

            WebUrl = properties.WebUrl;

            int initMessageId = writeInitiationMessage(startTime, properties.ListItem.Title);

            List<Exception> errors = new List<Exception>();

            DepartmentInformationBL deps = new DepartmentInformationBL();

            {
                Exception error = deps.ValidateAllDepartmentData(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            {
                Exception error = deps.LoadAllDepartmentsFields(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            {
                Exception error = deps.CleanDeletedFields(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            {
                Exception error = deps.CleanDepartmentOrdering(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            {
                Exception error = deps.GetAllInternalFields(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            {
                Exception error = deps.CleanUpColumnWidth(WebUrl);
                if (error != null)
                    errors.Add(error);
            }

            writeCompletionMessage(startTime, properties.ListItem.Title, errors);

            properties.ListItem.Delete();

            removeMessage(initMessageId);

            resizeMessageList();
        }

        void removeMessage(int id)
        {
            using (SPSite spSite = new SPSite(WebUrl))
            {
                using (SPWeb spWeb = spSite.OpenWeb())
                {
                    SPList spList = spWeb.Lists[COBACKGROUNDSTATUS];
                    spList.Items.DeleteItemById(id);
                    spList.Update();
                }
            }
        }

        void resizeMessageList()
        {
            using (SPSite spSite = new SPSite(WebUrl))
            {
                using (SPWeb spWeb = spSite.OpenWeb())
                {
                    SPList spList = spWeb.Lists[COBACKGROUNDSTATUS];
                    if (spList.Items.Count > MAXITEMS)
                    {
                        SPQuery query = new SPQuery
                        {
                            Query = Query.Get(Query.ByCreated, SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now.AddDays(-MAXDAYS)))
                        };
                        SPListItemCollection items = spList.GetItems(query);
                        if (items.Count > 0)
                        {
                            List<SPListItem> l = new List<SPListItem>();
                            foreach (SPListItem item in items)
                                l.Add(item);
                            for (int i = l.Count - 1; i >= 0; i++)
                                l[i].Delete();
                            spList.Update();
                        }
                    }
                }
            }
        }

        int writeCompletionMessage(DateTime startTime, string title, List<Exception> errors)
        {
            DateTime endTime = DateTime.Now;
            TimeSpan ts = endTime - startTime;

            StringBuilder sb = new StringBuilder();
            if (ts.Hours > 0)
                sb.AppendFormat(ts.Hours > 1 ? "{0} hours " : "{0} hour ", ts.Hours);
            if (ts.Minutes > 0)
                sb.AppendFormat(ts.Minutes > 1 ? "{0} minutes " : "{0} minute ", ts.Minutes);
            if (ts.Seconds > 0)
                sb.AppendFormat(ts.Seconds > 1 ? "{0} seconds " : "{0} second ", ts.Seconds);
            string t = sb.ToString().Trim();
            sb = null;

            string message = string.Format(errors.Count > 0 ? NOT_OK_MESSAGE : OK_MESSAGE, title, endTime.ToShortDateString(), endTime.ToShortTimeString(), t, startTime.ToShortDateString(), startTime.ToShortTimeString());
            if (message.Length > 255)
                message = message.Substring(0, 255);

            const string BR = "<br />";
            sb = new StringBuilder();
            foreach (Exception e in errors)
            {
                sb.AppendFormat("{1}{0}", BR, e.Message);
                if (!string.IsNullOrEmpty(e.StackTrace))
                    sb.AppendFormat("Stack Trace: {1}{0}", BR, e.StackTrace.Replace(Environment.NewLine, BR));
                if (e.InnerException != null)
                {
                    sb.AppendFormat("Inner Exception: {1}{0}", BR, e.InnerException.Message);
                    if (!string.IsNullOrEmpty(e.InnerException.StackTrace))
                        sb.AppendFormat("Stack Trace: {1}{0}", BR, e.InnerException.StackTrace.Replace(Environment.NewLine, BR));
                }
                sb.Append("**** END OF ERROR ***");
            }
            string error = sb.ToString().Trim();
            sb = null;

            return writeMessage(message, error);
        }

        int writeInitiationMessage(DateTime startTime, string title)
        {
            string message = string.Format(INIT_MESSAGE, title, startTime.ToShortDateString(), startTime.ToShortTimeString());
            if (message.Length > 255)
                message = message.Substring(0, 255);

            return writeMessage(message, string.Empty);
        }

        int writeMessage(string message, string error)
        {
            using (SPSite spSite = new SPSite(WebUrl))
            {
                using (SPWeb spWeb = spSite.OpenWeb())
                {
                    SPList spList = spWeb.Lists[COBACKGROUNDSTATUS];
                    SPListItem item = spList.Items.Add();
                    item[TITLE] = message;
                    item[ERRORS] = error;
                    item.Update();
                    spList.Update();
                    return item.ID;
                }
            }
        }

        #endregion Methods

        #region Nested Types

        class Query
        {
            #region Fields

            public const string ByCreated = "<Where><Lt><FieldRef Name='Created' /><Value IncludeTimeValue='False' Type='DateTime'>{0}</Value></Lt></Where>";

            #endregion Fields

            #region Methods

            public static string Get(string query, params object[] args)
            {
                return string.Format(query, args);
            }

            #endregion Methods
        }

        #endregion Nested Types
    }
}